﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;

namespace Dycox.Drawing
{
    public class ShapeLink
    {
        public ShapeLink(DiagramShape startControl, int startHotPoint, DiagramShape endControl, int endHotPoint, DiagramLinkLineType type)
            : this(new DiagramEndPoint(startControl, startHotPoint), new DiagramEndPoint(endControl, endHotPoint), type)
        {
        }

        public ShapeLink(DiagramEndPoint start, DiagramEndPoint end, DiagramLinkLineType type)
        {
            if (start == null) throw new ArgumentNullException("start");
            if (end == null) throw new ArgumentNullException("end");

            _start = start;
            _end = end;

            LineType = type;

            _start.LocationChanged += EndPointLocationChanged;
            _end.LocationChanged += EndPointLocationChanged;
        }

        private void EndPointLocationChanged(object sender, EventArgs e)
        {
            Initialize();
        }

        private DiagramEndPoint _start;

        public DiagramEndPoint Start
        {
            get { return _start; }
        }

        private DiagramEndPoint _end;

        public DiagramEndPoint End
        {
            get { return _end; }
        }

        private DiagramLinkLineType _lineType;

        public DiagramLinkLineType LineType
        {
            get { return _lineType; }
            set
            {
                if (_lineType != value || _linkLine == null)
                {
                    _lineType = value;
                    Initialize();
                }
            }
        }

        private DiagramLine _linkLine;

        public DiagramLine LinkLine
        {
            get { return _linkLine; }
        }

        private void Initialize()
        {
            DiagramLine line = _linkLine;

            switch (_lineType)
            {
                case DiagramLinkLineType.Straight:
                    UpdateStraightLine(ref line);                    
                    break;
                case DiagramLinkLineType.RightAngle:
                    line = _linkLine;
                    UpdatePolyline(ref line);
                    break;
                case DiagramLinkLineType.Bezier:
                    throw new NotImplementedException();
                default:
                    throw new InvalidOperationException("Line type" + _lineType + " is not valid.");
            }

            if (_linkLine == null)
            {
                PropertyDescriptorCollection coll0, coll1;

                coll0 = TypeDescriptor.GetProperties(_linkLine);
                coll1 = TypeDescriptor.GetProperties(line);

                foreach (PropertyDescriptor p0 in coll0)
                {
                    PropertyDescriptor p1 = coll1[p0.Name];
                    if (p1 != null && p1.PropertyType.IsAssignableFrom(p0.PropertyType))
                        p1.SetValue(line, p0.GetValue(_linkLine));
                }

                line.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;

                _linkLine = line;
            }

        }

        private void UpdateStraightLine(ref DiagramLine line)
        {
            if (line == null)
                line = DiagramStraightLine.CreateLink(Start.TargetShape, Start.HotPointID, _end.TargetShape, _end.HotPointID);
            else
                ((DiagramStraightLine)line).Update(_start.TargetShape, _start.HotPointID, _end.TargetShape, _end.HotPointID);
        }

        private void UpdatePolyline(ref DiagramLine line)
        {
            PointF pt1 = _start.Location, pt2 = _end.Location;
            float x = pt2.X - pt1.X, y = pt2.Y - pt1.Y;
            int hpid2 = _end.HotPointID, hpid1 = _start.HotPointID;
            Direction dir;
            float turnning = 1f;

            if (hpid1 >= 6 && hpid1 <= 9 || hpid1 >= 14)
            {
                if (x >= 0) dir = Direction.East;
                else dir = Direction.West;

                if (hpid2 >= 6 && hpid2 <= 9 || hpid2 >= 14)
                    turnning = .5f;
            }
            else
            {
                if (y >= 0) dir = Direction.South;
                else dir = Direction.North;

                if (hpid2 >= 1 && hpid2 <= 5 || hpid2 >= 10 && hpid2 <= 13)
                    turnning = .5f;
            }

            if (line == null)
                line = DiagramPolyline.CreateLink(_start.TargetShape, _start.HotPointID, _end.TargetShape, _end.HotPointID, dir, turnning);
            else
                ((DiagramPolyline)line).Update(_start.TargetShape, _start.HotPointID, _end.TargetShape, _end.HotPointID, dir, turnning);
        }

    }
}
